<?php
namespace Leaps\Config;
use Closure;
use ArrayAccess;
class Repository implements ArrayAccess
{

    /**
     * 装载机实现
     *
     * @var \Leaps\Config\LoaderInterface
     */
    protected $loader;

    /**
     * 缓存键的解析。
     *
     * @var array
     */
    protected $parsed = array ();

    /**
     * 所有的配置项。
     *
     * @var array
     */
    protected $items = array ();

    /**
     * 加载后的回调处理
     *
     * @var array
     */
    protected $afterLoad = array ();

    /**
     * 创建一个新的配置库。
     *
     * @param \Leaps\Config\LoaderInterface $loader
     * @param string $environment
     * @return void
     */
    public function __construct(LoaderInterface $loader)
    {
        $this->loader = $loader;
    }

    /**
     * 给定的配置值是否存在。
     *
     * @param string $key
     * @return bool
     */
    public function has($key)
    {
        $default = microtime ( true );
        return $this->get ( $key, $default ) != $default;
    }

    /**
     * 确定是否存在一个配置组。
     *
     * @param string $key
     * @return bool
     */
    public function hasGroup($key)
    {
        list ( $group, $item ) = $this->parseKey ( $key );
        return $this->loader->exists ( $group );
    }

    /**
     * 获取指定的配置值。
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function get($key, $default = null)
    {
        list ( $group, $item ) = $this->parseKey ( $key );
        $this->load ( $group);
        return array_get ( $this->items [$group], $item, $default );
    }

    /**
     * 设置一个给定的配置值。
     *
     * @param string $key
     * @param mixed $value
     * @return void
     */
    public function set($key, $value)
    {
        list ( $group, $item ) = $this->parseKey ( $key );
        $this->load ( $group );
        if ( is_null ( $item ) ) {
            $this->items [$group] = $value;
        } else {
            array_set ( $this->items [$group], $item, $value );
        }
    }

    /**
     * 加载配置组。
     *
     * @param string $key
     * @param string $namespace
     * @param string $collection
     * @return void
     */
    protected function load($group)
    {
        if ( isset ( $this->items [$group] ) ) {
            return;
        }
        $items = $this->loader->load ( $group );
        if ( isset ( $this->afterLoad [$group] ) ) {
            $items = $this->callAfterLoad ( $group, $items );
        }
        $this->items [$group] = $items;
    }

    /**
     * 调用加载后的回调处理
     *
     * @param string $namespace
     * @param string $group
     * @param array $items
     * @return array
     */
    protected function callAfterLoad($group, $items)
    {
        $callback = $this->afterLoad [$group];
        return call_user_func ( $callback, $this, $group, $items );
    }


    /**
     * 注册后的加载回调
     *
     * @param string $group
     * @param Closure $callback
     * @return void
     */
    public function afterLoading($group, Closure $callback)
    {
        $this->afterLoad [$group] = $callback;
    }

    /**
     * 获取装载机实例。
     *
     * @return \Leaps\Config\LoaderInterface
     */
    public function getLoader()
    {
        return $this->loader;
    }

    /**
     * 设置装载机实例
     *
     * @param \Leaps\Config\LoaderInterface $loader
     * @return void
     */
    public function setLoader(LoaderInterface $loader)
    {
        $this->loader = $loader;
    }

    /**
     * 解析一个键到名称空间、组和项目。
     *
     * @param string $key
     * @return array
     */
    public function parseKey($key)
    {
        if ( isset ( $this->parsed [$key] ) ) {
            return $this->parsed [$key];
        }
        $segments = explode ( '.', $key );
        $group = $segments [0];
        if ( count ( $segments ) == 1 ) {
            $parsed = array (
                    $group,
                    null
            );
        } else {
            $item = implode ( '.', array_slice ( $segments, 1 ) );

            $parsed = array (
                    $group,
                    $item
            );
        }
        return $this->parsed [$key] = $parsed;
    }

    /**
     * 获取处理后回调阵列。
     *
     * @return array
     */
    public function getAfterLoadCallbacks()
    {
        return $this->afterLoad;
    }

    /**
     * 获取所有配置项
     *
     * @return array
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * 确定是否存在给定的配置选项。
     *
     * @param string $key
     * @return bool
     */
    public function offsetExists($key)
    {
        return $this->has ( $key );
    }

    /**
     * 获取一个配置选项。
     *
     * @param string $key
     * @return bool
     */
    public function offsetGet($key)
    {
        return $this->get ( $key );
    }

    /**
     * 设置一个配置选项。
     *
     * @param string $key
     * @param string $value
     * @return void
     */
    public function offsetSet($key, $value)
    {
        $this->set ( $key, $value );
    }

    /**
     * 取消设置配置选项。
     *
     * @param string $key
     * @return void
     */
    public function offsetUnset($key)
    {
        $this->set ( $key, null );
    }
}
